package com.example.rxohosaudio.ability;

import com.example.audioprocessor.AudioProcessor;
import com.example.rxohosaudio.ResourceTable;
import com.example.rxharmonyaudio.StreamAudioPlayer;
import com.example.rxharmonyaudio.StreamAudioRecorder;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Slider;
import ohos.agp.components.Text;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.IBundleManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Permissions;

public class StreamAbility extends Ability {
    private HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "StreamAbilitySlice");

    static final int BUFFER_SIZE = 2048;
    static final int MY_PERMISSION_REQUEST = 134;
    static final int PROGRESS_SPEED = 100;
    static final int DIALOG_DURATION = 2000;
    private Button mBtnStart;
    private Slider mRatioBar;
    private Text mRatioValue;
    private Button mBtnPlay;
    private Button mBtnPlayChanged;
    private Permissions mPermissions;
    private StreamAudioRecorder mStreamAudioCapturer;
    private StreamAudioPlayer mStreamAudioPlayer;
    private FileOutputStream mFileOutputStream;
    private AudioProcessor mAudioProcessor;
    private File mOutputFile;
    private byte[] mBuffer;
    private boolean mIsRecording = false;
    private float mRatio = 1;

    @Override
    public void onStart(final Intent intent) {
        super.onStart(intent);
//        super.setMainRoute(StreamAbilitySlice.class.getName());
        setUIContent(ResourceTable.Layout_ability_stream);

        mBtnStart = (Button) findComponentById(ResourceTable.Id_mBtnStart);
        mRatioBar = (Slider) findComponentById(ResourceTable.Id_mRatio);
        mRatioValue = (Text) findComponentById(ResourceTable.Id_mRatioValue);
        mBtnPlay = (Button) findComponentById(ResourceTable.Id_mBtnPlay);
        mBtnPlayChanged = (Button) findComponentById(ResourceTable.Id_mBtnPlayChanged);
        mStreamAudioCapturer = StreamAudioRecorder.getInstance();
//        mAudioRecorder = AudioRecorder_new.getInstance();
        mStreamAudioPlayer = StreamAudioPlayer.getInstance();
        mAudioProcessor = new AudioProcessor(BUFFER_SIZE);
        mBuffer = new byte[BUFFER_SIZE];
        if (mBtnStart != null) {
            mBtnStart.setClickedListener(component -> start());
        }
        if (mBtnPlay != null) {
            mBtnPlay.setClickedListener(component -> play());
        }
        if (mBtnPlayChanged != null) {
            mBtnPlayChanged.setClickedListener(component -> playChanged());
        }
        mRatioBar.setValueChangedListener(new Slider.ValueChangedListener() {
            @Override
            public void onProgressUpdated(final Slider slider, final int progress, final boolean fromUser) {
                HiLog.info(label, "mRatioBar onProgressUpdated");
                mRatio = (float) progress / PROGRESS_SPEED;
                mRatioValue.setText(String.valueOf(mRatio));
            }

            @Override
            public void onTouchStart(final Slider slider) {
            }

            @Override
            public void onTouchEnd(final Slider slider) {
            }
        });
    }

    public void start() {
        HiLog.info(label, "mBtnStart clicked  start");
        if (canRequestPermission("ohos.permission.MICROPHONE")
                || canRequestPermission("ohos.permission.READ_USER_STORAGE")
                || canRequestPermission("ohos.permission.USER_AUDIO")
                || canRequestPermission("ohos.permission.WRITE_USER_STORAGE")
                || canRequestPermission("ohos.permission.MODIFY_AUDIO_SETTINGS")
                || canRequestPermission("ohos.permission.READ_MEDIA")
                || canRequestPermission("ohos.permission.WRITE_MEDIA")) {

            getContext().requestPermissionsFromUser(new String[]{"ohos.permission.MICROPHONE",
                    "ohos.permission.READ_USER_STORAGE",
                    "ohos.permission.USER_AUDIO",
                    "ohos.permission.WRITE_USER_STORAGE",
                    "ohos.permission.MODIFY_AUDIO_SETTINGS",
                    "ohos.permission.READ_MEDIA",
                    "ohos.permission.WRITE_MEDIA"}, MY_PERMISSION_REQUEST);
        }

        if (mIsRecording) {
            stopRecord();
            mBtnStart.setText("Start");
            mIsRecording = false;
        } else {
            boolean isPermissionsGranted = (verifySelfPermission("ohos.permission.WRITE_USER_STORAGE")
                    == IBundleManager.PERMISSION_GRANTED) && (verifySelfPermission("ohos.permission.MODIFY_AUDIO_SETTINGS")
                    == IBundleManager.PERMISSION_GRANTED);
            if (!isPermissionsGranted) {
                getContext().requestPermissionsFromUser(new String[]{"ohos.permission.MICROPHONE",
                        "ohos.permission.READ_USER_STORAGE",
                        "ohos.permission.USER_AUDIO",
                        "ohos.permission.WRITE_USER_STORAGE",
                        "ohos.permission.MODIFY_AUDIO_SETTINGS",
                        "ohos.permission.READ_MEDIA",
                        "ohos.permission.WRITE_MEDIA"}, MY_PERMISSION_REQUEST);
            } else {
                HiLog.warn(label, "34444errt");
                startRecord();
                mBtnStart.setText("Stop");
                mIsRecording = true;
                mBtnPlay.setClickable(true);
            }
        }
    }

    private void startRecord() {
        HiLog.warn(label, "startRecord start");
        try {
            mOutputFile = new File("data/data/com.example.rxohosaudio/"
                    + File.separator + System.nanoTime() + ".stream.m4a");
            mOutputFile.createNewFile();
            mFileOutputStream = new FileOutputStream(mOutputFile);
//            Source source = new Source();
//            source.setRecorderAudioSource(Recorder.AudioSource.MIC);
//            //sample_rate :192000
//            //bit_rate :192000
//            //encode :aac
//            AudioProperty audioProperty = new AudioProperty.Builder()
//                    .setRecorderSamplingRate(AUDIO_SAMPLE_RATE_HZ)
//                    .setRecorderBitRate(AUDIO_BIT_RATE_HZ)
//                    .setRecorderAudioEncoder(Recorder.AudioEncoder.AAC)
//                    .build();
//            StorageProperty storageProperty = new StorageProperty.Builder()
//                    .setRecorderFile(mOutputFile)
//                    .setRecorderMaxDurationMs(-1)
//                    .setRecorderMaxFileSizeBytes(-1)
//                    .build();

//            boolean ret = mAudioRecorder.prepareRecord(source, Recorder.OutputFormat.MPEG_4,
//                    audioProperty, storageProperty);
//            mAudioRecorder.startRecord();
            mStreamAudioCapturer.start(new StreamAudioRecorder.AudioDataCallback() {
                @Override
                public void onAudioData(final byte[] data, final int size) {
                    HiLog.warn(label, "startRecord   start222");
                    if (mFileOutputStream != null) {
                        try {
                            HiLog.debug(label, "AMP", "amp " + calcAmp(data, size));
                            mFileOutputStream.write(data, 0, size);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

                @Override
                public void onError() {
                    new EventHandler(EventRunner.getMainEventRunner()).postSyncTask(new Runnable() {
                        @Override
                        public void run() {
                            new ToastDialog(StreamAbility.this).setText("Record fail").setDuration(DIALOG_DURATION).show();
                            mBtnStart.setText("Start");
                            mIsRecording = false;
                        }
                    });
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int calcAmp(final byte[] data, final int size) {
        int amplitude = 0;
        for (int i = 0; i + 1 < size; i += 2) {
            short value = (short) (((data[i + 1] & 0x000000FF) << 8) + (data[i + 1] & 0x000000FF));
            amplitude += Math.abs(value);
        }
        amplitude /= (double) size / 2;
        return amplitude / 2048;
    }

    private void stopRecord() {
        mStreamAudioCapturer.stop();
        try {
            if (mFileOutputStream != null) {
                mFileOutputStream.close();
            }
            mFileOutputStream = null;
            mIsRecording = false;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void play() {
        HiLog.info(label, "mBtnPlay clicked  play");
        if (mOutputFile == null) {
            return;
        }
        io.reactivex.Observable.just(mOutputFile)
                .subscribeOn(Schedulers.io())
                .subscribe(file -> {
                    try {
                        mStreamAudioPlayer.init();
                        FileInputStream inputStream = new FileInputStream(file);
                        int read;
                        while ((read = inputStream.read(mBuffer)) > 0) {
                            mStreamAudioPlayer.play(mBuffer, read);
                        }
                        inputStream.close();
                        mStreamAudioPlayer.release();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }, Throwable::printStackTrace);
    }

    public void playChanged() {
        HiLog.info(label, "mBtnPlayChanged clicked  playChanged");
        if (mOutputFile == null) {
            return;
        }
        Observable.just(mOutputFile)
                .subscribeOn(Schedulers.io())
                .subscribe(file -> {
                    try {
                        mStreamAudioPlayer.init();
                        FileInputStream inputStream = new FileInputStream(file);
                        int read;
                        while ((read = inputStream.read(mBuffer)) > 0) {
                            mStreamAudioPlayer.play(mRatio == 1
                                            ? mBuffer
                                            : mAudioProcessor.process(mRatio, mBuffer,
                                    StreamAudioRecorder.DEFAULT_SAMPLE_RATE),
                                    read);
                        }
                        inputStream.close();
                        mStreamAudioPlayer.release();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }, Throwable::printStackTrace);
    }

    private Permissions getPermissions() {
        if (mPermissions == null) {
            mPermissions = new Permissions();
        }
        return mPermissions;
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mIsRecording = false;
    }

    @Override
    public void onForeground(final Intent intent) {
        super.onForeground(intent);
    }

}
